/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pkg4funparse;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Stack;
import pkg4fungeneric.Code;
import pkg4funlex.Analyzer;
import pkg4funlex.Token;

/**
 *
 * @author l
 */
public class PredictiveAnalyzer {

    private static ArrayList<Integer> rules[];
    private static ArrayList<Symbol> SYMBOL;
    private static Stack <Integer> ss;
    private static int[][] M;
    private static int END;
    private static int LAMBDA;
    private static int START;

    public static void init() {
        rules = Data.RULES;
        SYMBOL = Data.SYMBOLS;
        M = Data.M;
        START = 0;
        END = Data.N_TERM_SIZE;
        LAMBDA = Data.N_TERM_SIZE+1;
        ss = new Stack<Integer>();
        run();
    }

    public static void run() {
        Token tk;
        Symbol cur, top;
        int sp, rp, tp; /* ponteiro pros SIMBOLOS e REGRAS*/

        ss.push(END);
        ss.push(START);
        tk = Analyzer.getNextToken();

        while (true) {
            sp = (Integer) ss.lastElement();
            top = SYMBOL.get(sp);

            if (top.type == Symbol.Types.TERMINAL) {
                if (sp == END) System.exit(0);
                if (tk.getType().equals(top.value)) {
                    ss.pop();
                    tk = Analyzer.getNextToken();
                } else erro(tk, top);
            }
            else {
                tp = (Integer) Data.tkInd.get(tk.getType());
                rp = M[sp][Data.decode(tp)];
                if (rp == Code.ERRO) erro(tk, top);
                ss.pop();
                System.out.print(String.format("%1$-" + "<LITERAIS_ARIT>".length() + "s", top.value) + " ==>   ");
                for (int i = 0; i < rules[rp].size(); i++) {
//                    ArrayList<Integer> rule = (ArrayList<Integer>) rules[rp];
                    int code = rules[rp].get(i);
                    cur = SYMBOL.get(code);
                    System.out.print(cur.value + " ");
                }
                System.out.println();
                for (int i = rules[rp].size() - 1; i >= 0; --i)
                    if(rules[rp].get(i) != LAMBDA) ss.push(rules[rp].get(i));
            }
        }
    }

    private static void erro(Token tk, Symbol top) {
        System.out.println("Erro sintático em " + top.value + ", na linha " + tk.getLinenum()
                + " esperado: " + top.value + " veio " + tk.getType());
        System.exit(1);
    }
}
























//        System.out.println(Data.N_TERM_SIZE + " " + Data.TERM_SIZE + " " + Data.SYMBOLS.size());

//        System.out.println("\nSYMBOL[START]: " + SYMBOL.get(START).value + "\nSYMBOL[END]: " + SYMBOL.get(END).value + "\nEND: " + END);

//            System.out.println("top.value: " + top.value);
//            System.out.print("ss: ");
//            for (int i = 0; i < ss.size(); i++) {
//                int ind = (Integer) ss.get(i);
//                System.out.print(SYMBOL.get(ind).value + " ");
//            }
//            System.out.println();

            //a = nexttoken;
            //X = ss.last;

//                System.out.println("T symbolo: "+top.value+" token: "+tk.getType());
//                System.out.println("=======================\nNT symbolo: "+top.value+" token: "+tk.getType());

//                System.out.println("tk = " + tk.getType() + "tkInd.get(" + tk.getType() + ") = " + tp
//                        + "\nsp = " + sp + " SYMBOL.get(" + sp + ") = " + SYMBOL.get(sp).value
//                        + "\nrules[" + sp + "] = ");
//                for (int i = 0; i < Data.TERM_SIZE; i++) {
//                    if (M[sp][i] == -1) {
//                        continue;
//                    }
//                    System.out.print("rp:"+M[sp][i]+":"+"rules[rp]:"+rules[M[sp][i]]+":");
//                    ArrayList<Integer> rule = (ArrayList<Integer>) rules[M[sp][i]];
//                    for (Integer code : rule) {
//                        Symbol syy = (Symbol) SYMBOL.get(code);
//                        System.out.print(syy.value + " ");
//
//                    }
//
//                }
//                System.out.println();